<template>
  <div class="fx-confirm" ref="confirmDom" :class="{close:confirmClose}" :style="confirmStyle">
    <div class="fx-confirm-title" v-if="showTitle" @mousedown.stop.prevent="dragMousedown">
      <span>{{ title }}</span>
      <em v-if="showClose" @click="cancelClick('close','icon')"><i class="iconfont icon-multiply fs10"/></em>
    </div>
    <div class="content">
      <slot></slot>
      <span>{{ content }}</span>
    </div>
    <div class="footer">
      <fx-button class="mr15" v-if="showCancelButton" :loading="cancelLoading" :round="roundButton"
                 @click="cancelClick('cancel','btn')">
        {{ cancelText }}
      </fx-button>
      <fx-button type="primary" v-if="showDefineButton" :loading="defineLoading" :round="roundButton"
                 @click="defineClick">
        {{ defineText }}
      </fx-button>
    </div>
  </div>
  <div class="fx-confirm-modal" v-if="showModal" :class="{close:confirmClose}" @click="cancelClick('close','modal')"/>
</template>

<script lang="ts">
import { computed, defineComponent, onBeforeUnmount, onMounted, PropType, reactive, ref } from 'vue'
import fxButton from '@/base/button/button.vue'
import mitt, { Emitter } from 'mitt'
import { getSize } from '@/base/hooks'

export declare interface ConfirmProps {
  title: string;
  width: string;
  top: string;
  content: string;
  defineText: string;
  cancelText: string;
  showClose: boolean;
  showTitle: boolean;
  showModal: boolean;
  closeOnModal: boolean;
  closeOnEscape: boolean;
  showCancelButton: boolean;
  showDefineButton: boolean;
  roundButton: boolean;
}

export default defineComponent({
  name: 'FConfirm',
  components: {
    fxButton
  },
  props: {
    // 标题
    title: {
      type: String as PropType<string>,
      default: '提示'
    },
    // 宽度
    width: {
      type: String as PropType<string>,
      default: '420px'
    },
    // 距离顶部距离
    top: {
      type: String as PropType<string>,
      default: '60px'
    },
    // 内容
    content: {
      type: String as PropType<string>,
      default: null
    },
    // 确定按钮文字
    defineText: {
      type: String as PropType<string>,
      default: '确定'
    },
    // 取消按钮文字
    cancelText: {
      type: String as PropType<string>,
      default: '取消'
    },
    // 是否显示关闭按钮
    showClose: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    // 是否显示标题
    showTitle: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    // 是否模态层
    showModal: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    // 是否通过遮罩层关闭
    closeOnModal: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    // 是否通过ESC关闭
    closeOnEscape: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    // 是否显示取消按钮
    showCancelButton: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    // 是否显示确定按钮
    showDefineButton: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    // 圆角按钮
    roundButton: {
      type: Boolean as PropType<boolean>,
      default: false
    }
  },
  setup (props: ConfirmProps) {
    const confirmMitt: Emitter = mitt()
    // 组件dom
    const confirmDom = ref<HTMLElement>()
    // 是否关闭
    const confirmClose = ref<boolean>(false)
    // 是否关闭
    const defineLoading = ref<boolean>(false)
    // 是否关闭
    const cancelLoading = ref<boolean>(false)
    // 弹窗样式
    const confirmStyle = computed(() => {
      const winW = document.documentElement.clientWidth
      const width = getSize(props.width, 420)
      return {
        width: `${width}px`,
        left: `${(winW - width) / 2}px`,
        top: props.top
      }
    })
    // 取消/关闭点击
    const cancelClick = (type: 'close' | 'cancel', from: 'btn' | 'modal' | 'icon' | 'esc'): void => {
      if (!props.closeOnModal && from === 'modal') return
      if (!props.closeOnEscape && from === 'esc') return
      confirmMitt.emit('close', type)
    }
    // 确定关闭
    const defineClick = (): void => {
      confirmMitt.emit('define', 'define')
    }
    // 点击ESC退出
    const handleEscape = (): void => {
      cancelClick('close', 'esc')
    }
    // 关闭事件
    const closeConfirm = (): void => {
      confirmClose.value = true
      document.removeEventListener('keydown', handleEscape)
    }
    // 设置取消的loading
    const setCancelLoading = (val: boolean): void => {
      cancelLoading.value = val
    }
    // 设置确定的loading
    const setDefineLoading = (val: boolean): void => {
      defineLoading.value = val
    }
    // 拖拽开始
    const dragStart = ref<boolean>(false)
    // 拖动数据
    const dragInfo = reactive<{ disX: number, disY: number }>({
      disX: 0,
      disY: 0
    })
    // 拖拽拖动
    const dragMousemove = (ev: MouseEvent): void => {
      if (!dragStart.value || !confirmDom.value) return
      confirmDom.value.style.left = `${ev.x - dragInfo.disX}px`
      confirmDom.value.style.top = `${ev.y - dragInfo.disY}px`
    }
    // 拖拽结束
    const dragMouseup = (): void => {
      dragStart.value = false
      document.removeEventListener('mousemove', dragMousemove)
      document.removeEventListener('mouseup', dragMouseup)
    }
    // 拖拽开始
    const dragMousedown = (ev: MouseEvent): void => {
      if (!confirmDom.value) return
      dragStart.value = true
      const rect: DOMRect = confirmDom.value?.getBoundingClientRect()
      dragInfo.disX = ev.x - rect.x
      dragInfo.disY = ev.y - rect.y
      document.addEventListener('mousemove', dragMousemove)
      document.addEventListener('mouseup', dragMouseup)
    }
    onMounted(() => {
      document.addEventListener('keydown', handleEscape)
    })
    onBeforeUnmount(() => {
      document.removeEventListener('keydown', handleEscape)
    })

    return {
      confirmMitt,
      confirmDom,
      confirmClose,
      defineLoading,
      cancelLoading,
      confirmStyle,
      setCancelLoading,
      setDefineLoading,
      dragMousedown,
      closeConfirm,
      cancelClick,
      defineClick
    }
  }
})
</script>
